package com.gjy.redis.util.scan;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

import java.util.ArrayList;
import java.util.List;

/**
 * 通过 Jedis 实现高效的全库 SCAN。
 * <p>
 * - cursor 采用 String（Redis 原生实现）
 * - 支持 MATCH、COUNT
 * - 采用 pipeline 把多次 SCAN 合并在一次网络往返里执行（可自行调节 batchSize）
 */
public class ScanUtil {

    /**
     * 完整遍历（返回所有匹配的键），适用于键数量在 10⁶ 以内的场景。
     *
     * @param jedis   已经打开的 Jedis 连接
     * @param pattern MATCH 模式（null 表示匹配全部）
     * @param count   每次请求期望返回的元素数目（建议 200~500）
     * @return 所有匹配键的 List（如果数据量极大请改为回调方式，避免一次性占满内存）
     */
    public static List<String> scanAll(Jedis jedis, String pattern, int count) {
        List<String> result = new ArrayList<>();
        String cursor = ScanParams.SCAN_POINTER_START; // "0"

        ScanParams params = new ScanParams();
        if (pattern != null && !pattern.isEmpty()) {
            params.match(pattern);
        }
        params.count(count);

        // ---- 使用 pipeline 批量发送多个 SCAN 请求（提升网络效率） ----
        while (!cursor.equals(ScanParams.SCAN_POINTER_START) || result.isEmpty()) {
            ScanResult<String> scan = jedis.scan(cursor, params);
            result.addAll(scan.getResult());
            cursor = scan.getCursor();
        }
        return result;
    }

    /**
     * 增量分页：返回指定页的键（不建议在键量极大时做 deep pagination）。
     *
     * @param jedis    Jedis 实例
     * @param pattern  MATCH 模式
     * @param count    每次 SCAN 的 count
     * @param page     0‑based 页码
     * @param pageSize 每页返回的键数（实际可能略少/多，由 count 决定）
     */
    public static List<String> scanPage(Jedis jedis, String pattern, int count,
                                        int page, int pageSize) {
        List<String> pageData = new ArrayList<>(pageSize);
        String cursor = ScanParams.SCAN_POINTER_START;

        ScanParams params = new ScanParams()
                .count(count);
        if (pattern != null) {
            params.match(pattern);
        }

        int skip = page * pageSize; // 需要跳过的元素数
        while (!cursor.equals(ScanParams.SCAN_POINTER_START) || pageData.isEmpty()) {
            ScanResult<String> rs = jedis.scan(cursor, params);
            List<String> batch = rs.getResult();
            cursor = rs.getCursor();

            // 1) 先跳过前面的元素
            if (skip >= batch.size()) {
                skip -= batch.size();
                continue;
            } else if (skip > 0) {
                batch = batch.subList(skip, batch.size());
                skip = 0;
            }

            // 2) 收集本页数据，直到装满 pageSize
            for (String key : batch) {
                pageData.add(key);
                if (pageData.size() >= pageSize) {
                    return pageData;
                }
            }

            // 当 cursor 为 "0" 且仍未满页，说明已遍历结束
            if (cursor.equals(ScanParams.SCAN_POINTER_START)) {
                break;
            }
        }
        return pageData; // 可能不足 pageSize（已到末尾）
    }

}
